<script lang="ts">
import { useFocus } from '@peng_kai/kit/libs/vueuse';
import { useInjectDisabled } from 'ant-design-vue/es/config-provider/DisabledContext';

function getValidCode(str: string, len: number, validRE: RegExp) {
  const codeArr = [] as string[];

  for (let i = 0; i < str.length && codeArr.length < len; i++) {
    const code = str[i];

    if (validRE.test(code)) {
      codeArr.push(code);
    }
  }

  return codeArr.join('');
}
</script>

<script setup lang="ts">
const props = withDefaults(defineProps<{
  length?: number;
  validRE?: RegExp;
  disabled?: boolean;
  autoFocus?: boolean;
}>(), {
  length: 6,
  validRE: () => /\d/,
  disabled: false,
});
const value = defineModel('value', { default: '' });
const inputRef = ref<HTMLInputElement>();
const { focused } = useFocus(inputRef);
const isComposing = ref(false);
const antdDisabled = useInjectDisabled();
const disabled = computed(() => props.disabled !== undefined ? props.disabled : antdDisabled.value);

// function isFocused(i: number) {
//   return focused.value && (focused.value && value.value.length === i);
// }

function showItemCursor(i: number) {
  return !disabled.value && focused.value && (value.value.length === i);
}

function showItemBorder(i: number) {
  return !disabled.value
    && focused.value
    && (value.value.length === i || (value.value.length === props.length && i === props.length - 1));
}

function updateCode(text: string | undefined | null) {
  const inputEl = inputRef.value;

  if (inputEl)
    inputEl.value = value.value = getValidCode(text?.trim() ?? '', props.length, props.validRE);
}

function handleInput(ev: Event) {
  if (!isComposing.value) {
    const text = (ev.target as HTMLInputElement).value;
    updateCode(text);
  }
}

function handleCompositionStart() {
  isComposing.value = true;
}

function handleCompositionEnd(ev: CompositionEvent) {
  isComposing.value = false;
  const text = (ev.target as HTMLInputElement).value;
  updateCode(text);
}

function handlePaste(ev: ClipboardEvent) {
  const text = ev.clipboardData?.getData('text');
  updateCode(text);
}

onMounted(() => {
  props.autoFocus && nextTick().then(() => inputRef.value?.focus?.());
});
</script>

<template>
  <div>
    <div class="relative isolate w-full flex gap-1">
      <div
        v-for="i of props.length" :key="i"
        tabindex="-1"
        class="relative h-10.5 flex flex-1 items-center justify-center border-(1.5 sys-layer-a solid) rounded-2 bg-sys-layer-a p-0 text-center text-lg text-sys-text-head outline-none"
        :class="{
          [`before:(abs-center h-[40%] w-0.5 animate-pulse bg-brand content-[''])`]: showItemCursor(i - 1),
          '!border-sys-layer-e': showItemBorder(i - 1),
          'opacity-50 cursor-not-allowed': disabled,
        }"
        @click="inputRef?.focus()"
      >
        {{ value[i - 1] }}
      </div>
      <input
        ref="inputRef" :value="value" :disabled="disabled"
        class="absolute bottom-0 scale-10 text-black caret-sys-layer-e opacity-1 -z-1"
        type="text" :maxlength="props.length" inputmode="numeric"
        autocorrect="off" autocapitalize="off" autocomplete="off" spellcheck="false"
        @paste.prevent="handlePaste"
        @input.prevent="handleInput"
        @compositionstart="handleCompositionStart"
        @compositionend="handleCompositionEnd"
      >
    </div>
  </div>
</template>
